<script setup lang="ts">
import useElementSize from '@/hooks/useElementSize.ts'
import { computed, ref, useSlots, watch } from 'vue'
import { useIndexSwitch, useSwiperPlay } from './helpers.ts'
import { SwiperProps } from './index.ts'

const props = withDefaults(defineProps<SwiperProps>(), {
  autoplay: true,
  interval: 3000,
  duration: 300,
  scale: 0.6,
  pauseOnHover: true
})
const duration = `${props.duration}ms`

// 当前元素索引
const current = ref(0)
// 是否往下播放
const isNext = ref(true)
// 容器引用
const containerRef = ref()

// 获取子元素
const slots = useSlots()
const swiperItems = slots.default?.()[0].children || []
// 子元素数量
const count = <number>swiperItems.length

const size = useElementSize(containerRef)

const offsetX = computed(() => {
  if (!containerRef.value) return 0

  const width = size.width * count * (props.card ? props.scale : 1)
  const perWidth = width / count
  const offset = -(perWidth * current.value)

  return props.card ? offset + perWidth * 0.333 : offset
})

const emit = defineEmits<{
  change: [index: number]
}>()

watch(current, (value) => {
  emit('change', value)
})

const { toNext, toPrev, goTo } = useIndexSwitch(
  {
    current,
    count,
    isNext
  },
  () => resetPlay()
)
const { startPlay, pausePlay, resetPlay } = useSwiperPlay(props, toNext)

defineExpose({
  toNext,
  toPrev,
  goTo
})
</script>

<template>
  <div
    class="swiper"
    @mouseenter="pauseOnHover && pausePlay()"
    @mouseleave="pauseOnHover && startPlay()"
  >
    <div
      ref="containerRef"
      class="swiper-container"
      :style="{ transform: `translate3d(${offsetX}px, 0, 0)` }"
    >
      <div
        v-for="(item, index) in swiperItems"
        :key="index"
        :style="{ width: `${card ? scale * 100 : 100}%` }"
        :class="{ card, active: index === current }"
        class="swiper-item"
        @click="card && index !== current && goTo(index)"
      >
        <Component :is="item" />
      </div>
    </div>
  </div>
</template>

<style scoped>
.swiper {
  overflow: hidden;

  .swiper-container {
    height: 100%;
    display: flex;
    transition: v-bind(duration);
  }
}

.swiper-item {
  flex-shrink: 0;

  &.card {
    opacity: 0.4;
    transform: scale(0.8);
    border-radius: 0.4rem;
    overflow: hidden;
    cursor: pointer;
    transition: 0.3s;

    &.active {
      opacity: 1;
      transform: scale(1);
      cursor: default;
    }
  }
}
</style>